/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <objbase.h>
#include <pgl/mfc/PGLView.h>
#include <pgl/mfc/PGLDefaultEvent.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPGLView

IMPLEMENT_DYNCREATE(CPGLView, CView)

CPGLView::CPGLView()
: 
m_uPointedRegion(0), m_GDIpHelper( &m_GDIpInterface, m_pRegion), 
m_bPostResize(true),
m_eClipboardType(CPGLArchive::ClipBoardBitmap), m_bInitAutoScale(true)
{
	SetEvent( CPGLEventPtr(new CPGLDefaultEvent));
}

CPGLView::~CPGLView()
{
	m_pRegion.reset();
	ClearEvent();
}


BEGIN_MESSAGE_MAP(CPGLView, CView)
	//{{AFX_MSG_MAP(CPGLView)
	ON_WM_SIZE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_ERASEBKGND()
	ON_WM_DESTROY()
	ON_WM_MOUSEWHEEL()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
	ON_COMMAND(ID_EDIT_COPY, CPGLView::OnEditCopy)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPGLView drawing

void CPGLView::OnDraw(CDC* pDC)
{
	using namespace Gdiplus;
	using namespace gfxinterface;
	
	if (!m_pRegion)
		return;
	
	CRect clientRect;
	GetClientRect(clientRect);
	if((clientRect.Width() <= 0) || (clientRect.Height() <= 0))
		return ; // nothing to do here....

	Graphics graphics(pDC->m_hDC);

    try
    {
	if (IsResizeNeeded())
	{
		m_GDIpInterface.SetGraphics(&graphics);
		m_GDIpInterface.BeginPaint(pDC->m_hDC);
			m_pRegion->RefreshView(m_GDIpInterface,true);
		m_GDIpInterface.EndPaint();
		ResetResizeState();
	}

	m_GDIpHelper.Draw(clientRect, pDC->m_hDC, &graphics);
	
	// draw event
	if (m_pEvent)
		m_pEvent->Draw(graphics, clientRect);
    }
    catch(std::exception const& e)
    {
        AfxMessageBox(CString("An exception has occured:") + e.what());
    }
}

/////////////////////////////////////////////////////////////////////////////
// CPGLView diagnostics

#ifdef _DEBUG
void CPGLView::AssertValid() const
{
	CView::AssertValid();

}

void CPGLView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG

void CPGLView::SetTripleBuffering(bool on)
{
	m_GDIpHelper.SetTripleBuffering(on);
	InvalidateRect(NULL,FALSE);
}

void CPGLView::SetDirty()
{
	m_GDIpHelper.SetDirty();
	InvalidateRect(NULL,FALSE);
};

void CPGLView::SetFrontDirty()
{
	m_GDIpHelper.SetFrontDirty();
	InvalidateRect(NULL,FALSE);
};

void CPGLView::SetCacheDirty()
{
	m_GDIpHelper.SetCacheDirty();
	InvalidateRect(NULL,FALSE);
};

/////////////////////////////////////////////////////////////////////////////
// CPGLView message handlers

void CPGLView::OnSize(UINT nType, int cx, int cy) 
{
	using namespace Gdiplus;

	CView::OnSize(nType, cx, cy);


    try
    {
	    // setting interface...
	    m_GDIpInterface.SetMainBoundingBox(0,0,cx,cy);
	    SetDirty();
    }
    catch(std::exception const& e)
    {
        AfxMessageBox(CString("An exception has occured:") + e.what());
    }

	if (!m_pRegion)
		return;

	m_pRegion->SetViewport(0,0,cx,cy);
	PostResize();
}


void CPGLView::SetRegion(CPGLRegionPtr pRegion)
{
	m_pRegion = pRegion;
	m_GDIpHelper.SetRegion(pRegion);


	CRect rect;
	GetClientRect(&rect);

	if (rect.IsRectEmpty() || !pRegion)
		return;

	m_GDIpInterface.SetMainBoundingBox(rect.left,rect.top,rect.Width(),rect.Height());
	m_pRegion->SetViewport(rect.left,rect.top,rect.Width(),rect.Height());
	PostResize();
}

BOOL CPGLView::OnPreparePrinting(CPrintInfo* pInfo) 
{
	return DoPreparePrinting( pInfo );
}


void CPGLView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
//	CView::OnBeginPrinting(pDC, pInfo);
}

void CPGLView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
//	CView::OnEndPrinting(pDC, pInfo);
}

void CPGLView::OnPrint(CDC* pDC, CPrintInfo* pInfo) 
{	
	if (!m_pRegion)
		CView::OnPrint(pDC,pInfo);

	CPGLPrinter printer(&(*m_pRegion));
	printer.Print(pDC, pInfo);

}

void CPGLView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CView::OnLButtonDown(nFlags, point);

	// no region pointed...
	if (!m_pRegion)
		return;

	// keeping mouse
	SetCapture();

	// finding pointed region...
	CPGLPointD pglPoint( point.x, point.y);
	m_uPointedRegion = m_pRegion->FindPointedRegion( m_GDIpInterface, pglPoint);	

	// mouse is down
	m_mouse.LeftBtnPressed(point.x, point.y);

	// handling event
	if (m_pEvent)
	{
		m_pEvent->SetRegion(m_uPointedRegion);
		m_pEvent->OnLButtonDown(nFlags,point);
	}
}

void CPGLView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CView::OnLButtonUp(nFlags, point);

    if (!m_pRegion)
        return;

	//Releasing mouse
	ReleaseCapture();

	// stop mouse...
	m_mouse.Stop();
	m_mouse.Move(point.x,point.y);

	// handling event
	if (m_pEvent)
	{
		m_pEvent->SetRegion(m_uPointedRegion);
		m_pEvent->OnLButtonUp(nFlags, point);
	}

	m_mouse.LeftBtnReleased();
}


void CPGLView::OnRButtonUp(UINT nFlags, CPoint point) 
{
	CView::OnRButtonUp(nFlags, point);

    if (!m_pRegion)
        return;

	//Releasing mouse
	ReleaseCapture();

	// stop mouse...
	m_mouse.Stop();
	m_mouse.Move(point.x,point.y);

	// handling event
	if (m_pEvent)
	{
		m_pEvent->SetRegion(m_uPointedRegion);
		m_pEvent->OnRButtonUp(nFlags, point);
	}

	m_mouse.RightBtnReleased();
}

void CPGLView::OnMouseMove(UINT nFlags, CPoint point) 
{
	int lastx,lasty;
	CView::OnMouseMove(nFlags, point);

	if (!m_pRegion)
		return;

	if (!m_mouse.IsLeftBtnDown(lastx,lasty) && !m_mouse.IsRightBtnDown(lastx,lasty))
	{
		// find pointed region...
		CPGLPointD pglPoint( point.x, point.y);
		m_uPointedRegion = m_pRegion->FindPointedRegion( m_GDIpInterface, pglPoint);	
	}

	if (m_mouse.IsLeftBtnDown(lastx,lasty))
		m_mouse.LeftMove();
	if (m_mouse.IsRightBtnDown(lastx,lasty))
		m_mouse.RightMove();


	// handling event
	if (m_pEvent)
	{
		m_pEvent->SetRegion(m_uPointedRegion);
		m_pEvent->OnMouseMove(nFlags,point);
	}

	// update mouse
	m_mouse.Move(point.x,point.y);
}

void CPGLView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CView::OnRButtonDown(nFlags, point);

    if (!m_pRegion)
        return;

	// keeping mouse
	SetCapture();

	// finding pointed region...
	CPGLPointD pglPoint( point.x, point.y);
	m_uPointedRegion = m_pRegion->FindPointedRegion( m_GDIpInterface, pglPoint);	

	// mouse is down
	m_mouse.LeftBtnPressed(point.x, point.y);

	// handling event
	if (m_pEvent)
	{
		m_pEvent->SetRegion(m_uPointedRegion);
		m_pEvent->OnRButtonDown(nFlags,point);
	}
}

void CPGLView::OnEditCopy()
{
	if (!m_pRegion)
		return;

	CPGLArchive ar(m_pRegion);
	ar.ExportToClipBoard(m_eClipboardType,false, CPGLPointU((UINT)m_pRegion->GetView()->GetWidth(), (UINT)m_pRegion->GetView()->GetHeight()), CView::m_hWnd);
}


BOOL CPGLView::OnEraseBkgnd(CDC* pDC) 
{
	if (m_pRegion)	
		return TRUE;
	else
		return CView::OnEraseBkgnd(pDC);
}

void CPGLView::OnDestroy() 
{
	using namespace Gdiplus;

	CView::OnDestroy();

	m_GDIpHelper.Destroy();
	m_pRegion.reset();

	ClearEvent();
}

void CPGLView::SeralizeSettingsXML(CPGLArchive& ar)
{
	if (m_pRegion)
		m_pRegion->SerializeXML(ar);

	if (ar.IsLoading())
		SetDirty();
}

void CPGLView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	if (!m_pRegion)
		return;

    try
    {
	if (m_bInitAutoScale)
	{
		CClientDC dc(this);
		Gdiplus::Graphics graphics(dc.m_hDC);
		m_GDIpInterface.SetGraphics(&graphics);
		m_GDIpInterface.BeginPaint(dc.m_hDC);
			m_pRegion->ZoomAll(m_GDIpInterface,true);
		m_GDIpInterface.EndPaint();	
	}
    }
    catch(std::exception const& e)
    {
        AfxMessageBox(CString("An exception has occured:") + e.what());
    }

}

void CPGLView::SetEvent( CPGLEventPtr pEvent)
{
	ClearEvent();

	m_pEvent = pEvent;

	if( !m_pEvent)
		return;

	m_pEvent->SetParent(this);
	m_pEvent->SetGfx( &m_GDIpInterface);
	m_pEvent->SetRegion(m_uPointedRegion);
	m_pEvent->SetMouse(&m_mouse);
	m_pEvent->SetHelper(&m_GDIpHelper);
}

void CPGLView::ClearEvent()
{
	m_pEvent.reset();
}

BOOL CPGLView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	// handling event
	if (m_pEvent)
		m_pEvent->OnMouseWheel(nFlags,zDelta,pt);
	
	return CView::OnMouseWheel(nFlags, zDelta, pt);
}

void CPGLView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// handling event
	if (m_pEvent)
		m_pEvent->OnLButtonDblClk(nFlags, point);

	CView::OnLButtonDblClk(nFlags, point);
}


void CPGLView::OnRButtonDblClk(UINT nFlags, CPoint point) 
{
	// handling event
	if (m_pEvent)
		m_pEvent->OnRButtonDblClk(nFlags, point);
	
	CView::OnRButtonDblClk(nFlags, point);
}

void CPGLView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// handling event
	if (m_pEvent)
		m_pEvent->OnVScroll(nSBCode,nPos,pScrollBar);
	
	CView::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CPGLView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// handling event
	if (m_pEvent)
		m_pEvent->OnHScroll(nSBCode,nPos,pScrollBar);
	
	CView::OnHScroll(nSBCode, nPos, pScrollBar);
}
